@file:OptIn(ExperimentalMaterial3Api::class)
package com.maodou.core.ui.components

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import com.maodou.core.R

/**
 * 下拉刷新 + 上拉加载 统一封装：
 * - AppPullRefreshBox：包裹任意内容，支持下拉刷新指示器
 * - AppPullRefreshScrollableColumn：整个区域可滚动并支持下拉刷新
 * - RefreshableLazyColumn：带下拉刷新与列表末尾加载/错误/完成状态，并内置靠近底部触发加载
 * - FullscreenLoading/Empty/Error：常用全屏状态组件
 */

@Composable
fun AppPullRefreshBox(
    refreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier,
    indicatorAlignment: Alignment = Alignment.TopCenter,
    content: @Composable () -> Unit
) {
    val state = rememberPullToRefreshState()
    PullToRefreshBox(
        isRefreshing = refreshing,
        onRefresh = onRefresh,
        modifier = modifier,
        state = state,
        indicator = {
            PullToRefreshDefaults.Indicator(
                isRefreshing = refreshing,
                state = state,
                modifier = Modifier.align(indicatorAlignment),
                containerColor = MaterialTheme.colorScheme.surface,
                color = MaterialTheme.colorScheme.primary
            )
        }
    ) {
        content()
    }
}

@Composable
fun AppPullRefreshScrollableColumn(
    refreshing: Boolean,
    onRefresh: () -> Unit,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    content: @Composable () -> Unit
) {
    val state = rememberPullToRefreshState()
    val scrollState = rememberScrollState()
    PullToRefreshBox(
        isRefreshing = refreshing,
        onRefresh = onRefresh,
        modifier = modifier.fillMaxSize(),
        state = state,
        indicator = {
            PullToRefreshDefaults.Indicator(
                isRefreshing = refreshing,
                state = state,
                modifier = Modifier.align(Alignment.TopCenter),
                containerColor = MaterialTheme.colorScheme.surface,
                color = MaterialTheme.colorScheme.primary
            )
        }
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .verticalScroll(scrollState)
                .padding(contentPadding)
        ) {
            content()
        }
    }
}

sealed interface LoadMoreState {
    data object Idle : LoadMoreState
    data object Loading : LoadMoreState
    data class Error(val message: String? = null) : LoadMoreState
    data object End : LoadMoreState
}

@Composable
fun <T> RefreshableLazyColumn(
    items: List<T>,
    key: ((T) -> Any)? = null,
    refreshing: Boolean,
    onRefresh: () -> Unit,
    loadMoreState: LoadMoreState,
    onLoadMore: () -> Unit,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    loadMoreEnabled: Boolean = true,
    loadMoreThreshold: Int = 2,
    listState: LazyListState = rememberLazyListState(),
    emptyContent: (@Composable () -> Unit)? = null,
    itemContent: @Composable (T) -> Unit
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = refreshing,
        onRefresh = onRefresh,
        modifier = modifier.fillMaxSize(),
        state = state,
        indicator = {
            PullToRefreshDefaults.Indicator(
                isRefreshing = refreshing,
                state = state,
                modifier = Modifier.align(Alignment.TopCenter),
                containerColor = MaterialTheme.colorScheme.surface,
                color = MaterialTheme.colorScheme.primary
            )
        }
    ) {
        if(emptyContent != null && items.size == 0) emptyContent()
        else LazyColumn(
            state = listState,
            modifier = Modifier.fillMaxSize(),
            contentPadding = contentPadding
        ) {
            itemsIndexedWrapper(items = items, key = key, itemContent = itemContent)
            // Load more footer
            item {
                when (loadMoreState) {
                    is LoadMoreState.Idle -> Unit
                    is LoadMoreState.Loading -> FooterLoading()
                    is LoadMoreState.Error -> FooterError(message = loadMoreState.message, onRetry = onLoadMore)
                    is LoadMoreState.End -> FooterEnd()
                }
            }
        }
    }

    if (loadMoreEnabled) {
        OnBottomReached(
            state = listState,
            buffer = loadMoreThreshold,
            enabled = items.isNotEmpty() && loadMoreState is LoadMoreState.Idle,
            onLoadMore = onLoadMore
        )
    }
}

@Composable
private fun OnBottomReached(
    state: LazyListState,
    buffer: Int = 2,
    enabled: Boolean = true,
    onLoadMore: () -> Unit
) {
    LaunchedEffect(state, buffer, enabled) {
        if (!enabled) return@LaunchedEffect
        snapshotFlow { state.layoutInfo }
            .map { info ->
                val total = info.totalItemsCount
                val lastVisible = info.visibleItemsInfo.lastOrNull()?.index ?: 0
                total > 0 && lastVisible >= total - 1 - buffer
            }
            .distinctUntilChanged()
            .filter { it }
            .collect { onLoadMore() }
    }
}

private fun <T> LazyListScope.itemsIndexedWrapper(
    items: List<T>,
    key: ((T) -> Any)?,
    itemContent: @Composable (T) -> Unit
) {
    if (key != null) {
        items(items, key = { key(it) }) { item -> itemContent(item) }
    } else {
        items(items) { item -> itemContent(item) }
    }
}

@Composable
fun FooterLoading() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
    }
}

@Composable
fun FooterError(message: String? = null, onRetry: () -> Unit) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        contentAlignment = Alignment.Center
    ) {
        LinkText(
            text = message ?: "加载失败，点击重试",
            onClick = onRetry,
            color = MaterialTheme.colorScheme.primary
        )
    }
}

@Composable
fun FooterEnd(tip: String = "没有更多了", color: Color = MaterialTheme.colorScheme.outline) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .padding(12.dp),
        contentAlignment = Alignment.Center
    ) {
        Text(text = tip, style = MaterialTheme.typography.bodySmall, color = color)
    }
}

// 常用全屏状态
@Composable
fun FullscreenLoading(modifier: Modifier = Modifier) {
    Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
    }
}

@Composable
fun FullscreenEmpty(
    text: String = "暂无数据",
    modifier: Modifier = Modifier
) {
    Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text(text = text, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
    }
}

@Composable
fun FullscreenError(
    text: String = "加载失败，点击重试",
    modifier: Modifier = Modifier,
    onRetry: () -> Unit
) {
    Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        LinkText(text = text, onClick = onRetry)
    }
}

// ===== Previews =====
@Preview(showBackground = true)
@Composable
private fun PreviewRefreshableLazyColumn_Idle() {
    val data = remember { (1..20).map { "Item $it" } }
    RefreshableLazyColumn(
        items = data,
        refreshing = false,
        onRefresh = {},
        loadMoreState = LoadMoreState.Idle,
        onLoadMore = {},
        contentPadding = PaddingValues(8.dp)
    ) { item ->
        Text(
            text = item,
            modifier = Modifier.padding(12.dp),
            style = MaterialTheme.typography.bodyMedium
        )
    }
}

@Preview(showBackground = true)
@Composable
private fun PreviewAppPullRefreshScrollableColumn() {
    AppPullRefreshScrollableColumn(
        refreshing = false,
        onRefresh = {},
        contentPadding = PaddingValues(16.dp)
    ) {
        Text(text = "整个区域可下拉刷新（可滚动）", style = MaterialTheme.typography.titleMedium)
    }
}

@Composable
fun <S, T> RefreshableStickySectionedLazyColumn(
    sections: List<S>,
    itemsOf: (S) -> List<T>,
    refreshing: Boolean,
    onRefresh: () -> Unit,
    loadMoreState: LoadMoreState,
    onLoadMore: () -> Unit,
    modifier: Modifier = Modifier,
    contentPadding: PaddingValues = PaddingValues(0.dp),
    loadMoreEnabled: Boolean = true,
    loadMoreThreshold: Int = 2,
    listState: LazyListState = rememberLazyListState(),
    headerKey: ((S) -> Any)? = null,
    itemKey: ((T) -> Any)? = null,
    headerContainerColor: Color = MaterialTheme.colorScheme.surface,
    headerContent: @Composable (S) -> Unit,
    itemContent: @Composable (T) -> Unit
) {
    val state = rememberPullToRefreshState()

    PullToRefreshBox(
        isRefreshing = refreshing,
        onRefresh = onRefresh,
        modifier = modifier.fillMaxSize(),
        state = state,
        indicator = {
            PullToRefreshDefaults.Indicator(
                isRefreshing = refreshing,
                state = state,
                modifier = Modifier.align(Alignment.TopCenter),
                containerColor = MaterialTheme.colorScheme.surface,
                color = MaterialTheme.colorScheme.primary
            )
        }
    ) {
        LazyColumn(
            state = listState,
            modifier = Modifier.fillMaxSize(),
            contentPadding = contentPadding
        ) {
            sections.forEach { section ->
                stickyHeader(key = headerKey?.invoke(section)) {
                    Box(
                        modifier = Modifier
                            .fillMaxWidth()
                            .background(headerContainerColor)
                            .padding(vertical = 8.dp, horizontal = 12.dp)
                    ) {
                        headerContent(section)
                    }
                }
                val data = itemsOf(section)
                if (itemKey != null) {
                    items(data, key = { itemKey(it) }) { item ->
                        itemContent(item)
                    }
                } else {
                    items(data) { item ->
                        itemContent(item)
                    }
                }
            }
            // Load more footer
            item {
                when (loadMoreState) {
                    is LoadMoreState.Idle -> Unit
                    is LoadMoreState.Loading -> FooterLoading()
                    is LoadMoreState.Error -> FooterError(message = loadMoreState.message, onRetry = onLoadMore)
                    is LoadMoreState.End -> FooterEnd()
                }
            }
        }
    }

    if (loadMoreEnabled) {
        OnBottomReached(
            state = listState,
            buffer = loadMoreThreshold,
            enabled = sections.any { itemsOf(it).isNotEmpty() } && loadMoreState is LoadMoreState.Idle,
            onLoadMore = onLoadMore
        )
    }
}


@Composable
fun EmptyCenterLayout(
    modifier: Modifier = Modifier
        .fillMaxSize()
        .background(color = Color.Transparent),
    text: String = "暂无数据",
) {
    val context = LocalContext.current

    Box(
        modifier = modifier,
        contentAlignment = Alignment.Center
    ) {
        Column(
            modifier = Modifier.fillMaxWidth(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
        ) {
            Box(
                modifier = Modifier,
                contentAlignment = Alignment.Center
            ) {
                Image(
                    painter = painterResource(R.mipmap.ic_data_empty),
                    contentDescription = null,
                    contentScale = ContentScale.FillBounds,
                )
            }

            VSpacer(15.dp)

            Text(
                text = text,
                color = Color(0xffcccccc),
                style = TextStyle(
                    fontWeight = FontWeight.Light,
                    fontSize = 14.sp,
                    lineHeight = 20.sp,
                    textAlign = TextAlign.Center
                ),
            )
        }
    }
}

// ===== Preview: 粘性分组列表示例 =====
@Preview(showBackground = true)
@Composable
private fun PreviewRefreshableStickySectionedLazyColumn() {
    val sections = remember {
        listOf(
            "A" to (1..5).map { "A-$it" },
            "B" to (1..8).map { "B-$it" },
            "C" to (1..6).map { "C-$it" }
        )
    }
    RefreshableStickySectionedLazyColumn<Pair<String, List<String>>, String>(
        sections = sections,
        itemsOf = { it.second },
        refreshing = false,
        onRefresh = {},
        loadMoreState = LoadMoreState.End,
        onLoadMore = {},
        contentPadding = PaddingValues(8.dp),
        headerContent = { section ->
            Text(text = section.first, style = MaterialTheme.typography.titleMedium)
        },
        itemContent = { item ->
            Text(text = item, modifier = Modifier.padding(12.dp), style = MaterialTheme.typography.bodyMedium)
        }
    )
}